using System;
using System.ComponentModel;
using System.Data;
using System.Text;
using System.Web;
using System.Web.UI;

namespace MyControls.DataSources.CompositeHierarchicalDataSource {
    /// <summary>
    /// The <see cref="IHierarchyData"/> implementation for <see cref="CompositeHierarchicalDataSource"/>.
    /// </summary>
    public class CompositeHierarchyData : IHierarchyData, ICustomTypeDescriptor {
        private DataRow _row;
        private DataRelation _childRelation;
        private DataRelation _parentRelation;

        internal CompositeHierarchyData(DataRow dataRow) {
            _row = dataRow;
            if (_row != null && _row.Table != null) {
                DataRelationCollection rels = _row.Table.ParentRelations;
                if (rels.Count > 0) _parentRelation = rels[0];
                rels = _row.Table.ChildRelations;
                if (rels.Count > 0) _childRelation = rels[0];
            }
        }

        #region IHierarchyData Members

        IHierarchicalEnumerable IHierarchyData.GetChildren() {
            if (_childRelation == null) {
                return new CompositeHierarchicalEnumerable(null);
            }
            return new CompositeHierarchicalEnumerable(_row.GetChildRows(_childRelation));
        }

        IHierarchyData IHierarchyData.GetParent() {
            if (_parentRelation == null) {
                return null;
            }
            DataRow[] parentRows = _row.GetParentRows(_parentRelation);
            if (parentRows.Length == 0) {
                return null;
            }
            return new CompositeHierarchyData(parentRows[0]);
        }

        bool IHierarchyData.HasChildren {
            get {
                if (_childRelation == null) {
                    return false;
                }
                return _row.GetChildRows(_childRelation).Length > 0;
            }
        }

        object IHierarchyData.Item {
            get { return _row; }
        }

        string IHierarchyData.Path {
            get {
                if (_row == null || _row.Table == null) return String.Empty;
                DataTable table = _row.Table;
                string tableName = table.TableName;
                string nameSpace = table.Namespace;
                StringBuilder sb = new StringBuilder(nameSpace);
                sb.Append(':');
                sb.Append(tableName);
                bool first = true;
                foreach (DataColumn key in table.PrimaryKey) {
                    if (first) {
                        sb.Append('/');
                        first = false;
                    }
                    else {
                        sb.Append(',');
                    }
                    sb.Append(key.ColumnName);
                    sb.Append("='");
                    sb.Append(Convert.ToString(_row[key]).Replace(@"'", @"\'"));
                    sb.Append("'");
                }
                return sb.ToString();
            }
        }

        string IHierarchyData.Type {
            get {
                if (_row == null || _row.Table == null) return String.Empty;
                return _row.Table.Namespace + ':' + _row.Table.TableName;
            }
        }

        #endregion

        #region ICustomTypeDescriptor Members

        System.ComponentModel.AttributeCollection ICustomTypeDescriptor.GetAttributes() {
            return System.ComponentModel.AttributeCollection.Empty;
        }

        string ICustomTypeDescriptor.GetClassName() {
            return GetType().Name;
        }

        string ICustomTypeDescriptor.GetComponentName() {
            return null;
        }

        TypeConverter ICustomTypeDescriptor.GetConverter() {
            return null;
        }

        EventDescriptor ICustomTypeDescriptor.GetDefaultEvent() {
            return null;
        }

        PropertyDescriptor ICustomTypeDescriptor.GetDefaultProperty() {
            string defaultPropertyName = String.Empty;
            if (_row != null && _row.Table != null && _row.Table.Columns.Count != 0) {
                defaultPropertyName = _row.Table.Columns[0].ColumnName;
            }
            return new CompositeHierarchyDataPropertyDescriptor(defaultPropertyName);
        }

        object ICustomTypeDescriptor.GetEditor(Type editorBaseType) {
            return null;
        }

        EventDescriptorCollection ICustomTypeDescriptor.GetEvents(Attribute[] attributes) {
            return null;
        }

        EventDescriptorCollection ICustomTypeDescriptor.GetEvents() {
            return null;
        }

        PropertyDescriptorCollection ICustomTypeDescriptor.GetProperties(Attribute[] attributes) {
            System.Collections.Generic.List<PropertyDescriptor> list = new System.Collections.Generic.List<PropertyDescriptor>();

            DataColumnCollection columns = _row.Table.Columns;
            if (_row != null && _row.Table != null) {
                foreach (DataColumn column in _row.Table.Columns) {
                    list.Add(new CompositeHierarchyDataPropertyDescriptor(column.ColumnName));
                }
            }

            return new PropertyDescriptorCollection(list.ToArray());
        }

        PropertyDescriptorCollection ICustomTypeDescriptor.GetProperties() {
            return ((ICustomTypeDescriptor)this).GetProperties(null);
        }

        object ICustomTypeDescriptor.GetPropertyOwner(PropertyDescriptor pd) {
            if (pd is CompositeHierarchyDataPropertyDescriptor) {
                return this;
            }

            return null;
        }

        #endregion

        /// <summary>
        /// A private PropertyDescriptor for <see cref="CompositeHierarchyData"/>.
        /// </summary>
        private class CompositeHierarchyDataPropertyDescriptor : PropertyDescriptor {
            private string _name;

            public CompositeHierarchyDataPropertyDescriptor(string name)
                : base(name, null) {
                _name = name;
            }


            public override Type ComponentType {
                get {
                    return typeof(CompositeHierarchyData);
                }
            }

            public override bool IsReadOnly {
                get {
                    return true;
                }
            }

            public override Type PropertyType {
                get {
                    return typeof(string);
                }
            }

            public override bool CanResetValue(object o) {
                return false;
            }

            public override object GetValue(object o) {
                CompositeHierarchyData data = o as CompositeHierarchyData;
                if (data != null &&
                    data._row != null &&
                    data._row.Table != null &&
                    data._row.Table.Columns.Contains(_name)) {
                    return data._row[_name];
                }

                return String.Empty;
            }

            public override void ResetValue(object o) {
                return;
            }

            public override void SetValue(object o, object value) {
            }

            public override bool ShouldSerializeValue(object o) {
                return true;
            }
        }
    }
}
